package io;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import main.ProgramOptions;

import components.Goal;
import components.Operator;
import components.PrePostCond;
import components.PrevailCond;
import components.Variable;

public class IoHandler {
	/**
	 * reads input file
	 * and fill the vectors with the components
	 * @param fileName
	 * @param vars
	 * @param goals
	 * @param operators
	 * @throws NumberFormatException
	 * @throws Exception
	 */
	public static void ParseFile
			(String fileName,Vector<components.Variable> vars, Vector<components.Goal> goals, Vector<components.Operator> operators) 
				throws NumberFormatException, Exception{
		
		operators.clear();
		goals.clear();
		vars.clear();
		//opening a file
		FileInputStream fstream = new FileInputStream(fileName);
	    DataInputStream in = new DataInputStream(fstream);
	    BufferedReader br = new BufferedReader(new InputStreamReader(in));
	    String line;
	    
	    //skip first 5 lines
	    br.readLine();
	    br.readLine();
	    boolean costs=(0==Integer.parseInt(br.readLine()));
	    br.readLine();
	    br.readLine();
	    
	    //getting number of vars line
	    line=br.readLine();
	    int numOfVars = Integer.parseInt(line);
	    
	    //getting variables
		for (int i=0;i<numOfVars;i++){
	    	line=br.readLine();
	    	StringTokenizer tok=new StringTokenizer(line," ");
	    	components.Variable var = 
	    		new components.Variable(tok.nextToken(),Integer.parseInt(tok.nextToken()),Integer.parseInt(tok.nextToken()),i);
	    	vars.add(var);
	    }
		//skip another 2 lines
		br.readLine();
		br.readLine();
		
		//get initial state
		for (int i=0;i<numOfVars;i++){
	    	line=br.readLine();
	    	vars.elementAt(i).setState(Integer.parseInt(line));
		}
		
		//get number of goals
		br.readLine();
		br.readLine();
		line=br.readLine();
	    int numOfGoals = Integer.parseInt(line);
		
	    //getting goals
	    for (int i=0;i<numOfGoals;i++){
	    	line=br.readLine();
	    	StringTokenizer tok=new StringTokenizer(line," ");
	    	components.Goal g= new components.Goal(vars.elementAt(Integer.parseInt(tok.nextToken())),Integer.parseInt(tok.nextToken()));
	    	goals.add(g);
	    }
	    
	    br.readLine();
	    int numOfOperators=Integer.parseInt(br.readLine());
	    for (int i=0;i<numOfOperators;i++){
	    	br.readLine();
	    	String name=br.readLine();
	    	int numOfPrevail=Integer.parseInt(br.readLine());
	    	Vector<PrevailCond> prev = new Vector<PrevailCond>();
	    	for (int j=0;j<numOfPrevail;j++){
	    		StringTokenizer tok= new StringTokenizer(br.readLine()," ");
	    		int a=Integer.parseInt(tok.nextToken());
	    		int b=Integer.parseInt(tok.nextToken());
	    		PrevailCond p= new PrevailCond(vars.elementAt(a), b);
	    		prev.add(p);
	    	}
	    	int numOfPrepost=Integer.parseInt(br.readLine());
	    	Vector<PrePostCond> prep = new Vector<PrePostCond>();
	    	for (int j=0;j<numOfPrepost;j++){
	    		if (0!=Integer.parseInt(br.readLine()))
	    			throw new Exception("Does not support conditional effects");
	    		StringTokenizer tok= new StringTokenizer(br.readLine()," ");
	    		int a=Integer.parseInt(tok.nextToken());
	    		int b=Integer.parseInt(tok.nextToken());
	    		int c=Integer.parseInt(tok.nextToken());
	    		
	    		PrePostCond p= new PrePostCond(vars.elementAt(a), b,c);
	    		prep.add(p);
	    	}
	    	int cost;
	    	if (costs){
	    		cost=1;
	    		br.readLine();
	    	}else cost=Integer.parseInt(br.readLine());
	    	operators.add(new Operator(name,prep,prev,cost));
	    	br.readLine();
	    }    
	    in.close();
	}
	/**
	 * writes the output file
	 * @param outputFile
	 * @param inputFile
	 * @param vars
	 * @param goals
	 * @param operators
	 * @throws NumberFormatException
	 * @throws Exception
	 */
	public static void outputToFile 
			(String outputFile,String inputFile,Vector<components.Variable> vars,Vector<components.Goal> goals,Vector<components.Operator> operators) 
				throws NumberFormatException, Exception{
		File f=new File(outputFile);
	    FileOutputStream fop=new FileOutputStream(f);
	    
	    
	    FileInputStream fstream = new FileInputStream(inputFile);
	    DataInputStream in = new DataInputStream(fstream);
	    BufferedReader br = new BufferedReader(new InputStreamReader(in));
	    //copy first 6 lines
		for (int i=0;i<6;i++)
			fop.write((br.readLine()+"\n").getBytes());
	    for (Variable i:vars)
	    	 fop.write(i.toString2().getBytes());
	    fop.write("end_variables\nbegin_state\n".getBytes());
	    for (Variable i:vars){
	    	 fop.write((i.getInitVal()+"\n").getBytes());
	    }
	    fop.write("end_state\nbegin_goal\n".getBytes());
	    fop.write((goals.size()+"\n").getBytes());
	    for (Goal i:goals)
	    	 fop.write(i.toString2().getBytes());
		fop.write("end_goal\n".getBytes());
		fop.write((operators.size()+"\n").getBytes());
		for (Operator i:operators)
			fop.write(("begin_operator\n"+i.toString2()+"end_operator\n").getBytes());
		
		in.close();
		fop.close();
	}
	/**
	 * reads config file
	 */
	public static void inputConfigurationFile(){
		Properties prop = new Properties();
		try{
			prop.load(new FileInputStream("properties.conf"));
		}catch (IOException e){
			ProgramOptions.lastInputFolder=null;
		}
		
		ProgramOptions.lastInputFolder=((String)prop.get("INPUT FOLDER"));
		ProgramOptions.lastOutputFolder=((String)prop.get("OUTPUT FOLDER"));
	}
	/**
	 * writes config file
	 */
	public static void outputConfigurationFile(){
		Properties prop = new Properties();
		try{
			prop.load(new FileInputStream("properties.conf"));
		}catch (IOException e){
			ProgramOptions.lastInputFolder=null;
		}
		prop.setProperty("INPUT FOLDER", new File(ProgramOptions.inputFile).getParent());
		prop.setProperty("OUTPUT FOLDER", new File(ProgramOptions.outputFile).getParent());
		
		try {
			prop.store(new FileOutputStream("properties.conf"), null);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	

}
